`timescale 1 ns /  100 ps
module uart_slave_wrapper(
	clock,
	resetn,
	writedata,
	read,
	write,
	chip_select,
	address,
	
	rx,
	
	readdata,
	wait_request,
	rx_interruptn,
	
	tx,
	);

// port definition
input clock, resetn, read, write, chip_select;
input [1:0] address;
input [7:0] writedata;
input rx;

output [7:0] readdata;
output wait_request, rx_interruptn;
output tx;


// variables
// slave_wrapper uart_tx
wire tx_fifo_writeenable, tx_fifo_readenable, tx_fifo_empty, tx_fifo_full;
wire [7:0] tx_fifo_readdata;
wire uart_tx_start, uart_tx_done;
wire wait_request_uart_tx;
// slave_wrapper uart_rx
wire rx_fifo_writeenable, rx_fifo_readenable, rx_fifo_empty, rx_fifo_full, rx_data_ready;
wire [7:0] rx_fifo_readdata, rx_fifo_writedata;
wire wait_request_uart_rx;

// state variables
// slave wrapper
integer IDLE=2'b00, WAIT_TX_FIFO = 2'b01, WAIT_RX_FIFO = 2'b10, DUMMY = 2'b11;
reg [1:0]state, next_state;
// uart_tx
integer UART_TX_IDLE = 2'b00, UART_TX_TRANSMIT = 2'b01;
reg [2:0] uart_tx_state, uart_tx_state_next;

// state outputs;
// slave wrapper
assign wait_request_uart_tx = (state == WAIT_TX_FIFO && tx_fifo_full == 1) || (state == IDLE && chip_select && write && tx_fifo_full);
//assign wait_request_uart_rx = (state == WAIT_RX_FIFO && rx_fifo_empty == 1) || (state == IDLE && chip_select && read && rx_fifo_empty);
assign wait_request_uart_rx = 0;
assign wait_request = wait_request_uart_tx | wait_request_uart_rx;
assign tx_fifo_writeenable = (state == WAIT_TX_FIFO && tx_fifo_full == 0) || (state == IDLE && chip_select ==1 && write == 1 && tx_fifo_full == 0);
// uart_tx
assign uart_tx_start = uart_tx_state == UART_TX_IDLE && !tx_fifo_empty;
assign tx_fifo_readenable = uart_tx_start;
// uart_rx
assign rx_fifo_writeenable = (!rx_fifo_full) && (rx_data_ready);
assign rx_interruptn = rx_fifo_empty;
//assign rx_fifo_readenable = (state == WAIT_RX_FIFO && rx_fifo_empty == 0) || (state == IDLE && chip_select && read && rx_fifo_empty == 0);
assign rx_fifo_readenable = (state == IDLE && chip_select && read && rx_fifo_empty == 0);
assign readdata = rx_fifo_readdata;

wire[9:0] fifo_tx_count, fifo_rx_count;

// fifo uart_tx
fifo tx_fifo
(
	.clock(clock),
	.resetn(resetn),
	
	.writeenable(tx_fifo_writeenable),
	.writedata(writedata),
	.readenable(tx_fifo_readenable),
	.readdata(tx_fifo_readdata),
	
	.empty(tx_fifo_empty),
	.full(tx_fifo_full),

	.count(fifo_tx_count),
);

// fifo uart_rx
fifo rx_fifo
(
	.clock(clock),
	.resetn(resetn),
	
	.writeenable(rx_fifo_writeenable),
	.writedata(rx_fifo_writedata),
	.readenable(rx_fifo_readenable),
	.readdata(rx_fifo_readdata),
	
	.empty(rx_fifo_empty),
	.full(rx_fifo_full),
	.count(fifo_rx_count)
);

// uart_tx
uart_tx uart_tx_instance
(
	.clock(clock),
	.resetn(resetn),
	.data(tx_fifo_readdata),
	.start(uart_tx_start),
	.q(tx),
	.done(uart_tx_done)
);

// uart_rx
uart_rx uart_rx_instance
(
	.clock(clock),
	.resetn(resetn),
	.data(rx_fifo_writedata),
	.rx(rx),
	.ready(rx_data_ready)
);

// state machine uart_tx
always @(*)
begin
	case (uart_tx_state)
		UART_TX_IDLE:
			if (!tx_fifo_empty)
				uart_tx_state_next = UART_TX_TRANSMIT;
			else
				uart_tx_state_next = UART_TX_IDLE;
		UART_TX_TRANSMIT:
			if (uart_tx_done)
				uart_tx_state_next = UART_TX_IDLE;
			else
				uart_tx_state_next = UART_TX_TRANSMIT;
		default:
				uart_tx_state_next = UART_TX_IDLE;
			
	endcase
end

always @(posedge clock or negedge resetn)
begin
	if (resetn == 0)
		uart_tx_state <= UART_TX_IDLE;
	else
		uart_tx_state <= uart_tx_state_next;
end
		
// state machine slave_wrapper
always @(*)
begin
	case (state)
	IDLE:
		if (chip_select && write && tx_fifo_full)
			next_state = WAIT_TX_FIFO;
		/*else if (chip_select && read && rx_fifo_empty)
			next_state = WAIT_RX_FIFO;*/
		else
			next_state = IDLE;
	WAIT_TX_FIFO:
		if (tx_fifo_full == 0)
			next_state = IDLE;
		else
			next_state = WAIT_TX_FIFO;
	/*WAIT_RX_FIFO:
		if (rx_fifo_empty == 0)
			next_state = DUMMY;
		else
			next_state = WAIT_RX_FIFO;
	DUMMY:
		next_state = IDLE;*/
	default:
		next_state = IDLE;
	endcase
end
			

always @(posedge clock or negedge resetn)
begin
	if (resetn == 0)
		state <= IDLE;
	else
		state <= next_state;
end

endmodule
		
